var fs=require('fs');
var process=require('process');
function impexp_gen_cols(fkrule,modelobj,is_l10n)
{
	var fn	=modelobj._Config("field_names"+(is_l10n?"_l10n":""));
	var fdt	=modelobj._Config("field_datatypes"+(is_l10n?"_l10n":""));
	var fkm	=modelobj._Config("field_fkmodels"+(is_l10n?"_l10n":""));
//	throw {fn:fn,fdt:fdt,fkm:fkm};
	var coldata={cols:[],fks:[]};
	for (var i=0;i<fn.length;i++) {
		switch (fdt[i]) {
			case "":
				continue;
			case "fk":
				coldata.cols.push((fkrule=="id")?fn[i]:fn[i].replace(/_id$/,"_name"));
				coldata.fks.push(fkm[i]);
				break;
			default:
				coldata.cols.push(fn[i]);
				coldata.fks.push("");
				break;
		}
	}
	return coldata;
}

var MK_PASSWORD_PRE=["acer", "acid", "addy", "afro", "aged", "ahoy", "airy", "alga", "ally", "alma", "aloe", "alps", "amid","ammo", "anna", "anti", "ants", "aqua", "aunt", "area", "argh", "aris", "army", "arts", "axis", "band", "berg", "bike", "boat", "boys", "brim", "bump", "cain", "demo", "ding", "dish", "disk", "earn", "emit", "emmy", "face", "fact", "fist", "five", "fork", "fuse", "fuss", "game", "gaze", "girl", "hole", "isle", "joke", "king", "love", "more", "null", "only", "post", "rest", "soda", "star", "trim", "type", "uniq", "vest", "wink", "zorg"];

exports.add=[{
	_type:"functions",
	_section:"Admin",

	/**
	 * Function: Admin.mk_password
	 */	
	mk_password: function(mask) {
		if (!mask) mask="WDDDDD";
		var ret="";
		for (var i=0;i<mask.length;i++) {
			switch (mask[i]) {
				case "W":
					ret+=MK_PASSWORD_PRE[Math.floor(Math.random()*MK_PASSWORD_PRE.length)];
					break;
				case "D":
					ret+=Math.floor(Math.random()*10);
					break;
			}
		}
		return ret;
	},

	/**
	 * Function: Admin.cols_through_params_part
	 */
	cols_through_params_part: function(cols) {
		var t=this;
		if (!cols) return "";
		var r="";
		cols.split(/\s*,\s*/).forEach(function(c) {
			r+=c;
			r+="=";
			r+=t.F("Views","I",t.fields[c]);
			r+="&";
		});
		return r;
	},

	/**
	 * Function: Admin.cols_through_params_full
	 */
	cols_through_params_full: function(cols) {
		var t=this;
		if (!cols) return "";
		var r="";
		cols.split(/\s*,\s*/).forEach(function(c) {
			if (r) r+="&"; else r+="?";
			r+=c;
			r+="=";
			r+=t.F("Views","I",t.fields[c]);
		});
		return r;
	},

	/**
	 * Function: Admin.load_l10ns
	 */
	load_l10ns: function() {
		var t=this;
		this.l10n_all=this.site.models.L10N.List("list");
		this.l10n_pages=[];
		this.l10n_all.forEach(function(l) {
			t.l10n_pages.push({id:"l10n-"+l.id+"-block",name:l.name});
		});
	},

	/**
	 * Function Admin.mail_templates_add
	 */
	mail_templates_add: function(arr) {
		var cnt=0;
		for (var i=0;i<arr.length;i++) {
			var v=arr[i];
			var rw=this.site.models.MailTemplate.List("get_by_signature",{signature:v.signature});
			if (rw.length) continue;
			rw=this.site.models.MailTemplate.Create();
			rw.FetchLocales();
			rw.ApplyAdminFields(v);
			rw.SaveAll();
			cnt++;
		}
		return cnt;
	},

	/**
	 * Function Admin.rewrites_add
	 */
	rewrites_add: function(arr) {
		var cnt=0;
		for (var i=0;i<arr.length;i++) {
			var v=arr[i];
			var rw=this.site.models.Rewrite.List("get_by_signature",{signature:v.signature});
			if (rw.length) continue;
			rw=this.site.models.Rewrite.Create();
			for (var k in v) rw[k]=v[k];
			rw.SaveAll();
			cnt++;
		}
		return cnt;
	},

	/**
	 * Function: Admin.user_helper
	 */
	user_helper: function(mode,item) {
		switch (mode) {
			case "edit":
				var checked=[];
				if (item.id) this.site.models.UserEnrolled.List("list_of_user",{user_id:item.id}).forEach(function(i) {checked.push(i.role_id);});
				this.roles={
					available:this.site.models.Role.List(),
					checked: checked
				};
				return this.View("controllers/adminpanel/AutoAdminUser/edit_helper");
				break;
			case "save":
				var flag=false;
				var checked={};
				this.site.models.UserEnrolled.List("list_of_user",{user_id:item.id}).forEach(function(i) {checked[i.role_id]=i;});
				for (var k in this.fields) {
					var arr=k.match(/^roles-(\d+)$/);
					if (!arr) continue;
					flag=true;
					if (checked[arr[1]]) {
						delete checked[arr[1]];
					} else {
						var c=this.site.models.UserEnrolled.Create();
						c.user_id=item.id;
						c.role_id=arr[1];
						c.SaveAll();
					}
				}
				for (var k in checked) checked[k].Delete();
//				item.calc_no_roles=;
				item.SaveAll();
				break;
			default:
				throw new Error("user_helper - unknown mode="+mode);
		}
	},

	/**
	 * Function: Admin.cart_helper
	 */
	cart_helper: function(mode,cart) {
		var t=this;
		switch (mode) {
			case "edit":
				var cis=this.cart_items=[];
				if (cart.id) {
					this.site.models.CartItem.List("list_of_cart",{cart_id:cart.id}).forEach(function(ci) {
						// TODO only market items
						var mi=t.site.models.MarketItem.Get(ci.market_item_id);
						cis.push({
							id:mi.id,
							name:mi.name,
							code:mi.code,
							category_name:mi.category_name,
							category_code:mi.category_code,
							manufacturer_name:mi.manufacturer_name,
							amount:ci.amount,
							price:ci.price,
							price_now:mi.price
						});
					});
				}
				var arr=this.site.models.CartState.List();
				for (var i=0;i<arr.length;i++) if (arr[i].id>cart.state_id && !this.state_up) this.state_up=arr[i];
				return this.View("controllers/adminpanel/AutoAdminCart/edit_helper");
				break;
			case "save":
				var items=JSON.parse(this.fields.items);
				cart.FetchItems();
				var flag=false;
				for (var k in items) {
					var arr=k.match(/^(\d+)-amount/);
					if (arr) {
						var amount=cart.GetAmountOf({market_item_id:arr[1]});
						if (amount!=items[k]) {
							flag=true;
							var mi=t.site.models.MarketItem.Get(arr[1]);
							cart.Set({amount:items[k],market_item_id:arr[1],price:mi.price});
						}
					}
				}
				if (flag) cart.SaveAll();
				break;
			default:
				throw new Error("cart_helper - unknown mode="+mode);
		}
	},

	import_data: function(modelobj,config,table) {


		var t=this;
		var l10ns=this.site.models.L10N.List();
		var ret="";

		var coldata		=impexp_gen_cols(config.fkrule,modelobj,0);
		var coldatal	=impexp_gen_cols(config.fkrule,modelobj,1);


		var x=1;
		var y=0;
		var idcol=-1;
		for (var i=0;i<coldata.cols.length;i++) {
			if (table[y][x]!=coldata.cols[i]) throw "column "+(x+1)+" must be '"+coldata.cols[i]+"'";
//			if (coldata.cols[i]=="id") idcol=x;
			x++;
		}
		for (var i=0;i<coldatal.cols.length;i++) {
			for (var j=0;j<l10ns.length;j++) {
				if (table[y][x]!=coldatal.cols[i]+" / "+l10ns[j].code) throw "column "+(x+1)+" must be '"+coldatal.cols[i]+" / "+l10ns[j].code+"'";
				x++;
			}
		}
		if (table[0][0]!="id") throw "No 'id' column!";
		idcol=0;
		y++;
		var used_ids=[];
		var item;

		var fkeys={};
		function gen_fks(cd)
		{
			for (var i=0;i<cd.fks.length;i++) {
				if (!cd.fks[i]) continue;
				if (fkeys[cd.fks[i].model]) continue;
				var h=fkeys[cd.fks[i].model]={};
				t.site.models[cd.fks[i].model].ListFK().forEach(function(a) {
					h[a.name]=a.id;
				});
			}
		}
		gen_fks(coldata);
		gen_fks(coldatal);
		function gen_fk(val,fkdata)
		{
			if (val==="" || val===undefined || val===null) return null;
			var a=fkeys[fkdata.model][val];
			if (!a) {
				t.no_send_error_notification=1;
				throw ["No foreign key data for "+fkdata.name+"='"+val+"'", fkeys, val, fkdata, fkeys[fkdata.model][val]];
			}
			return a;
		}

        if (this.fields.missing_id.length) {
            var missing_id_fields = {}; this.fields.missing_id.split(',').forEach(function (v) { return missing_id_fields[v.trim()]=true;});
        }

		while (y<table.length) {
			var row=table[y];
			item=undefined;
			if (row[idcol]) {
				// Update
				item=modelobj.Get(row[idcol]);
				if (!item) throw "No item id="+row[idcol];
			} else {
                //-- тут может быть поиск по названию ± альтернативные поля, следует написать "инструкцию" поиска и замены
                //-- какие могут быть варианты пересечения? одно или несколько полей? что делать с рекурсивными совпадениями?
                if (this.fields.missing_id.length) {
                    var missing_id_values = {}; var missing_id_params = []; x=1;
                    for (var i=0;i<coldata.cols.length;i++) {
                        if (!coldata.fks[i] && missing_id_fields[coldata.cols[i]]) {
                            missing_id_params.push(coldata.cols[i] +' = :'+ coldata.cols[i]);
                            missing_id_values[coldata.cols[i]] = row[x];
                        } else if (missing_id_fields[coldata.fks[i].name]){
                            missing_id_params.push(coldata.fks[i].name + '= :' + coldata.fks[i].name);
                            missing_id_values[coldata.fks[i].name] = (config.fk==="id")?row[x]:gen_fk(row[x],coldata.fks[i]);
                        }
                        x++;
                    }
                    var missing_id_query = "SELECT id FROM " + modelobj._config.table + " WHERE " + missing_id_params.join (' AND ');

                    var res = this.site.sql.execute_and_fetch_single(missing_id_query, missing_id_values).shift();
                    //throw [coldata, missing_id_fields, missing_id_params, missing_id_values, missing_id_query,res];
                    if (res && res.id) {
                        item=modelobj.Get(res.id);
                    } else {
                        item=modelobj.Create();
                    }
                } else {
                    item=modelobj.Create();
                }
				// Insert
			}
			if (coldatal.cols.length) item.FetchLocales();
			x=1;
			for (var i=0;i<coldata.cols.length;i++) {
				if (!coldata.fks[i]) {
                    item[coldata.cols[i]]=row[x];
                } else {
                    item[coldata.fks[i].name]=(config.fk==="id")?row[x]:gen_fk(row[x],coldata.fks[i]);
                }
				x++;
			}
			for (var i=0;i<coldatal.cols.length;i++) {
				item[coldatal.cols[i]]="...";
				for (var j=0;j<l10ns.length;j++) {
					if (!coldatal.fks[i]) item.l10ns[l10ns[j].id][coldatal.cols[i]]=row[x]; else item.l10ns[l10ns[j].id][coldatal.fks[i].name]=(config.fk==="id")?row[x]:gen_fk(row[x],coldatal.fks[i]);
					x++;
				}
			}
			//if (y==2) throw item; 
			item.SaveAll();
			used_ids.push(item.id);
			
			y++;
		}
		ret="OK";
		return ret;
	},

	/**
	 * Function: Admin.export_data
	 *		
	 * Parameters:
	 *		modelobj							- model object = this.site.models.XXX
	 *		config
	 *		config.fk typeof String				- either 'id' or 'name'
	 *
	 * Returns:
	 *		typeof Array of Array of String		- export result, formatted as table
	 */
	export_data: function(modelobj,config) {
		var table=[];
		
		var l10ns=this.site.models.L10N.List();

		var cols	=impexp_gen_cols(config.fkrule,modelobj,0).cols;
		var colsl	=impexp_gen_cols(config.fkrule,modelobj,1).cols;
//		throw {cols:cols,colsl:colsl};

		var d=["id"];
		for (var i=0;i<cols.length;i++) d.push(cols[i]);
		for (var i=0;i<colsl.length;i++) for (var j=0;j<l10ns.length;j++) d.push(colsl[i]+" / "+l10ns[j].code);
		table.push(d);

		var models=modelobj.List();
		var helper;
		if (config.helper) helper=config.helper.match(/^(\w+)\.(\w+)$/);
		if (helper) this.F(helper[1],helper[2],"export_start",{models:models,cols:cols,colsl:colsl,table:table});
		models.forEach(function(m) {
			if (colsl.length) m.FetchLocales();
			var d=[m.id];
			for (var i=0;i<cols.length;i++) d.push(m[cols[i]]);
			for (var i=0;i<colsl.length;i++) for (var j=0;j<l10ns.length;j++) d.push(m.l10ns[l10ns[j].id][colsl[i]]);
			table.push(d);
		});
		if (helper) this.F(helper[1],helper[2],"export_end",{models:models,cols:cols,colsl:colsl,table:table});
		return table;
	},

	/**
	 *
	 */
	json_table_to_xlsx: function(table) {
		var dir=new fs.Directory("/tmp/impexp/");
		if (!dir.exists()) dir.create();
		var dir=new fs.Directory("/tmp/impexp/"+this.site.code.replace(/[^\w\-\.]+/g,"")+"/");
		if (!dir.exists()) dir.create();
		var rand=Math.floor(Math.random()*10000);
		var f1=new fs.File(dir.toString()+"json2xlsx-"+rand+".json");
		if (f1.exists()) f1.remove();
		f1.open("w");
		f1.write(JSON.stringify(table));
		f1.close();
		var f2=new fs.File(dir.toString()+"json2xlsx-"+rand+".xlsx");
		if (f2.exists()) f2.remove();

		var proc=new process.Process();
		var ret=proc.system(system.getcwd()+"/files/json_table_to_xlsx.pl "+f1.toString());
		//throw ret;
		f2.open("r");
		var r=f2.read();
		f2.close();
//		f1.remove();
//		f2.remove();
		return r;
	},

	json_table_to_xml: function(table) {
		return "<xml>TODO</xml>";
	},

	/**
	 *
	 */
	xlsx_to_json_table: function(data) {
		var rand=Math.floor(Math.random()*10000);
		var dir=new fs.Directory("/tmp/impexp/");
		if (!dir.exists()) dir.create();
		var dir=new fs.Directory("/tmp/impexp/"+this.site.code.replace(/[^\w\-\.]+/g,"")+"/");
		if (!dir.exists()) dir.create();
		var f1=new fs.File(dir.toString()+"xlsx2json-"+rand+".xlsx");
		if (f1.exists()) f1.remove();
		f1.open("w");
		f1.write(data);
		f1.close();
		var f2=new fs.File(dir.toString()+"xlsx2json-"+rand+".json");
		if (f2.exists()) f2.remove();

		var proc=new process.Process();
		proc.system(system.getcwd()+"/files/xlsx_to_json_table.pl "+f1.toString());
		f2.open("r");
		var r=JSON.parse(f2.read().toString("utf-8"));
		f2.close();
//		f2.remove();
//		f1.remove();
		return r;
	},

	all_bots_regexp: function() {
		return /(googlebot|YandexMetrika|YandexBot|bingbot|Mail\.RU_Bot|WebIndex|AhrefsBot|AdsBot-Google|YandexDirect|URLGrabber|YaDirectFetcher|MJ12bot|libwww-perl|SMTBot|srvmonjs bot|curl|crawler|yandex\.com\/bots|robot)/i;
	},

	send_error_notification: function(dump,config) {
		var t=this;

		if (!config) {
			if (!this.site) return;
			if (!this.site.error_notify) return;
			if (this.no_send_error_notification) {
				delete send_error_notification;
				return;
			}
		}
		if (system.env.HTTP_USER_AGENT && system.env.HTTP_USER_AGENT.match(this.F("Admin","all_bots_regexp"))) return;
		var en=config?config.error_notify:this.site.error_notify;
		if (en.constructor!=Array) en=[en];
		var subject=this.site.code+", lattenoir threw error";
		var fields="";
		function escape1(a) {
			if (typeof obj!="string") return a;
			return a.replace(/\n/g,"\\n",/\t/g,"\\t");
		}
		for (var k in this.fields) {
			fields+=k;fields+="=";
			switch (typeof this.fields[k]) {
				case "number":
					fields+=this.fields[k];
					break;
				case "undefined":
					fields+="&lt;undefined&gt;";
					break;
				default: 
					var tmp=this.fields[k].toString();
					if (tmp.length>1000) fields+=escape1(tmp.substr(0,1000)); else fields+=escape1(tmp);
					break;
			}
			fields+="\n";
		}

		if (typeof dump == "object") dump=this.Dumper(dump);
		var from="no-reply@"+(this.site.names?this.site.names[0]:this.site.domains[0]);
		var body="URL: "+this.action+"\n"+
				"IP: "+system.env.REMOTE_ADDR+"\n"+
				"User-agent: "+system.env.HTTP_USER_AGENT+"\n"+
				"Referer: "+system.env.HTTP_REFERER+"\n"+
				"User: (uid="+this.uid+", login="+(this.uid?this.user.login:"")+", name="+(this.uid?this.user.calc_full_name:"")+")\n\n"+
				"GET/POST fields:\n"+fields+"\n"+
				"Detected fid: " + t._error_fid + "\n"+
				"Detected header: " + t._error_header + "\n"+
				"ERROR DUMP:\n"+dump;
		var http=require("http");
		en.forEach(function(to) {
			if (to.match(/@/)) {
				var headers = {
					From: from,
					"Content-Type": 'text/plain; charset="UTF-8"'
				};
				var auth;
				require("mail").mail(to, subject, body, headers, auth);
			} else if (to.match(/^http/)) {
				var req=new http.ClientRequest(to);
				req.post={
					body:body,
					header:t._error_header||"",
					fid:t._error_fid||"",
					ip:system.env.REMOTE_ADDR,
					userinfo:t.uid+", login="+(t.uid?t.user.login:"")+", name="+(t.uid?t.user.calc_full_name:""),
					url:t.action
				};
				req.method="POST";
				req.send(true);
			}
		});
	}
}];

